﻿using System;
using System.Web;
using System.Web.Security;
using TimeProject.Engine;
using TimeProject.Engine.DbContent;
using TimeProject.Engine.DbModels;
using TimeProject.Engine.Security;
using WebMatrix.WebData;

namespace TimeProject.WebSite
{
    public sealed class RequestContext : IDisposable
    {
        private const string ContextKey = "key_RequestContext";

        private DateTime _requestTimestamp;
        private string _requestUsername;
        private TimeProjectDbContext _dbContext;
        private UserInfo _currentUser;

        /// <summary>
        /// Gets the request timestamp.
        /// </summary>
        public DateTime RequestTimestamp
        {
            get { return _requestTimestamp; }
        }

        /// <summary>
        /// Gets the request username.
        /// </summary>
        public string RequestUsername
        {
            get { return _requestUsername; }
        }

        /// <summary>
        /// Gets the current RequestContext.
        /// </summary>
        public static RequestContext Current
        {
            get
            {
                RequestContext context;

                HttpContext http = HttpContext.Current;

                if (http == null)
                {
                    throw new InvalidOperationException("The current HttpContext is not available.");
                }

                if (http.Items.Contains(ContextKey))
                {
                    context = (RequestContext)http.Items[ContextKey];
                }
                else
                {
                    context = new RequestContext();
                    http.Items.Add(ContextKey, context);
                }

                return context;
            }
        }

        /// <summary>
        /// Gets the db context.
        /// </summary>
        public TimeProjectDbContext Db
        {
            get
            {
                if (_dbContext == null)
                {
                    _dbContext = CreateDbContext();
                }
                return _dbContext;
            }
        }

        /// <summary>
        /// Gets the current user.
        /// </summary>
        public UserInfo CurrentUser
        {
            get
            {
                if (WebSecurity.IsAuthenticated == false)
                {
                    return null;
                }

                int userId = WebSecurity.CurrentUserId;

                if (!(userId > 0))
                {
                    return null;
                }

                if (_currentUser == null)
                {
                    User user = Current.Db.GetUser(userId);
                    if (user == null)
                    {
                        return null;
                    }

                    _currentUser = new UserInfo();
                    _currentUser.Roles = new UserRoles();
                    _currentUser.UserId = userId;
                    _currentUser.Username = WebSecurity.CurrentUserName;
                    _currentUser.FullName = user.FullName;

                    string[] roles = Roles.GetRolesForUser(WebSecurity.CurrentUserName);
                    foreach (string id in roles)
                    {
                        UserRole role = UserRoles.GetRole(id);
                        _currentUser.Roles.Add(role);
                    }
                }

                return _currentUser;
            }
        }

        /// <summary>
        /// Initializes the RequestContext.
        /// </summary>
        internal void Initialize()
        {
            _requestTimestamp = DateTime.Now;
            _requestUsername = WebSecurity.CurrentUserName;
        }

        /// <summary>
        /// Creates a new db context.
        /// </summary>
        /// <returns>Db context.</returns>
        internal static TimeProjectDbContext CreateDbContext()
        {
            return new TimeProjectDbContext("TimeProjectConnection",
                           () => new TimeProjectDbContext.TimestampData
                           {
                               RequestUsername = Current.RequestUsername,
                               RequestTimestamp = Current.RequestTimestamp
                           });
        }
        
        public void Dispose()
        {
            if (_dbContext != null)
            {
                _dbContext.Dispose();
            }
        }
    }
}